package wangjg.security.resource.factory.db.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;

@SuppressWarnings("unchecked")
public class BasicHibernateDAO<T, ID extends Serializable> {
	private static Log log = LogFactory.getLog(BasicHibernateDAO.class);
	@Autowired
	protected SessionFactory sessionFactory;
	
	protected Class<T> persistentClass;

	public BasicHibernateDAO() {
		this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
//		ParameterizedType pt=(ParameterizedType)getClass().getGenericSuperclass();
//		Type[] ta=pt.getActualTypeArguments();
//		this.persistentClass = (Class<T>) ta[0];
	}

	/**
	 * 取得当前Session.
	 */
	public Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	public T findById(ID id) {
		return this.get(id);
	}


	/**
	 * 保存新增或修改的对象.
	 */
	public void save(final T entity) {
		getSession().save(entity);
		log.debug("save entity: "+entity);
	}
	
	/**
	 * 保存新增或修改的对象.
	 */
	public void update(final T entity) {
		getSession().update(entity);
		log.debug("update entity: "+entity);
	}

	/**
	 * 保存新增或修改的对象.
	 */
	public void saveOrUpdate(final T entity) {
		getSession().saveOrUpdate(entity);
		log.debug("save entity:"+entity);
	}

	/**
	 * 合并对象.
	 */
	public void merge(final T entity) {
		getSession().merge(entity);
		log.debug("merge entity:"+entity);
	}

	/**
	 * 删除对象.
	 * 
	 * @param entity
	 *            对象必须是session中的对象或含id属性的transient对象.
	 */
	public void delete(final T entity) {
		getSession().delete(entity);
		log.debug("delete entity: "+entity);
	}

	/**
	 * 按HQL查询对象列表
	 * @param hql
	 * @param values
	 * @return 对象集合
	 */
	public List<T> query(final String hql, final Object... values) {
		return createQuery(hql, values).list();
	}
	
	public List<T> query(int firstResult,int maxResults, final String hql,final Object... values) {
		Query query = createQuery(hql, values);
		query.setFirstResult(firstResult);
		query.setMaxResults(maxResults);
		return query.list();
	}
	
	/**
	 * 按HQL查询唯一对象.
	 * 
	 * @param values
	 * 数量可变的参数,按顺序绑定.
	 */
	public Object queryUnique(final String hql, final Object... values) {
		return createQuery(hql, values).uniqueResult();
	}

	public int executeUpdate(final String hql, final Object... values) {
		return createQuery(hql, values).executeUpdate();
	}
	
	public List<T> findByProperty(String propertyName, Object value) {
		Criterion criterion = Restrictions.eq(propertyName, value);
		return this.findByCriteria(criterion);
	}

	public T findUniqueByProperty(String propertyName, Object value) {
		Criterion criterion = Restrictions.eq(propertyName, value);
		return this.findUniqueByCriteria(criterion);
	}

	protected T get(ID id) {
		return (T) getSession().get(persistentClass, id);
	}

	protected T load(ID id) {
		return (T) getSession().load(persistentClass, id);
	}

	protected T findUniqueByCriteria(Criterion... criterions) {
		Criteria crit = this.createCriteria(criterions);
		return (T) crit.uniqueResult();
	}

	protected List<T> findByCriteria(Criterion... criterions) {
		Criteria crit = this.createCriteria(criterions);
		return crit.list();
	}

	/**
	 * 根据查询HQL与参数列表创建Query对象.
	 * 
	 * 本类封装的find()函数全部默认返回对象类型为T,当不为T时使用本函数.
	 * 
	 * @param values
	 *            数量可变的参数,按顺序绑定.
	 */
	protected Query createQuery(final String queryString,
			final Object... values) {
		Assert.hasText(queryString, "queryString不能为空");
		Query query = getSession().createQuery(queryString);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return query;
	}
	
	protected Criteria createCriteria(final Criterion... criterions) {
		Criteria criteria = getSession().createCriteria(persistentClass);
		for (Criterion c : criterions) {
			criteria.add(c);
		}
		return criteria;
	}
}
